package org.vogelsk.archangelsk;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;

import org.vogelsk.archangelsk.ai.Commander;
import org.vogelsk.archangelsk.creatures.Bullet;
import org.vogelsk.archangelsk.creatures.GenericCreature;
import org.vogelsk.archangelsk.creatures.Tank;
import org.vogelsk.archangelsk.creatures.Wall;
import org.vogelsk.archangelsk.gui.TankImage;
import org.vogelsk.archangelsk.util.Command;
import org.vogelsk.archangelsk.util.Direction;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.renderscript.Font;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.GestureDetector.SimpleOnGestureListener;

@SuppressWarnings(value = { "all" })
public class Tanks extends SurfaceView {

	private Tank playerTank;

	private List<Tank> enemyTanks = new ArrayList<Tank>();
	private List<Bullet> bullets = new ArrayList<Bullet>();
	private List<Wall> structures = new ArrayList<Wall>();
	private Commander ai = new Commander();
    private GestureDetector gestureDetector;

	private int points;
	private boolean inGame = true;

	private Timer timer;
	private Bitmap bulletImage;
	private Bitmap appleImage;
	private Bitmap wallImage;
	private Bitmap intactWallImage;
	private Bitmap destroyedWallImage;
	private TankImage playerTankImage;
	private TankImage enemyTankImage;

	private Bitmap backgoround;
	private Bitmap tankLeftImage;
	private Bitmap tankRightImage;
	private Bitmap tankUpImage;
	private Bitmap tankDownImage;
	private Bitmap tankDestroyedImage;
	private SurfaceHolder holder;
	private TankGameThread gameLoopThread;

	public Tanks(Context context, Bitmap bulletImage, Bitmap intactWallImage,
			Bitmap destroyedWallImage, Bitmap tankLeftImage,
			Bitmap tankRightImage, Bitmap tankUpImage, Bitmap tankDownImage,
			Bitmap tankDestroyedImage) {
		super(context);
		this.bulletImage = bulletImage;
		this.intactWallImage = intactWallImage;
		this.destroyedWallImage = destroyedWallImage;
		this.tankLeftImage = tankLeftImage;
		this.tankRightImage = tankRightImage;
		this.tankUpImage = tankUpImage;
		this.tankDownImage = tankDownImage;
		this.tankDestroyedImage = tankDestroyedImage;

		gameLoopThread = new TankGameThread(this);
		holder = getHolder();

		holder.addCallback(new SurfaceHolder.Callback() {

			public void surfaceDestroyed(SurfaceHolder holder) {

				boolean retry = true;

				gameLoopThread.setRunning(false);

				while (retry) {

					try {

						gameLoopThread.join();

						retry = false;

					} catch (InterruptedException e) {

					}

				}

			}

			public void surfaceCreated(SurfaceHolder holder) {
				initGame();
				gameLoopThread.setRunning(true);

				gameLoopThread.start();

			}

			public void surfaceChanged(SurfaceHolder holder, int format,
					int width, int height) {
			}

		});
		this.requestFocus();
		this.setFocusableInTouchMode(true);
		//this.setLongClickable(true);
		gestureDetector =  new GestureDetector(this.getContext(),new TankGestureDetector());
		gestureDetector.setIsLongpressEnabled(true);

	}
	public synchronized void initGame() {
		setTank();
		initEnemies();
		bullets.clear();
		structures.clear();
		initWalls(15, true, 300);

		initWalls(22, false, 250);
		initWalls(15, true, 330);
		initWalls(22, false, 280);
		ai.setTanks(enemyTanks);
		ai.setTarget(playerTank);
		points = 0;
		// soundManager.init();
		// soundManager.toggle(tglbtnNewToggleButton.isSelected());
		URL url;

		playerTankImage = new TankImage(tankLeftImage, tankRightImage,
				tankUpImage, tankDownImage, tankDestroyedImage);
		enemyTankImage = new TankImage(tankLeftImage, tankRightImage,
				tankUpImage, tankDownImage, tankDestroyedImage);

		// enemyTankImage = new TankImage(enemyTankLeftImage,
		// enemyTankRightImage, enemyTankUpImage,
		// enemyTankDownImage,tankDestroyedImage);
	}


	public void onDraw(Canvas canvas) {
		canvas.drawColor(Color.BLACK);

		if (inGame) {
			Paint paint = new Paint();
			// canvas.drawBitmap(backgoround,50,50,paint);

			synchronized(this){ if (!getStructures().isEmpty()) {
				for (Wall wall : getStructures())
					if (wall != null) {
						if (wall.isDestroyed())
							wallImage = getDestroyedWallImage();
						else
							wallImage = getIntactWallImage();

						canvas.drawBitmap(wallImage, wall.getX(), wall.getY(),
								paint);
					}
			}}

			Matrix mat = new Matrix();
	        mat.postRotate(playerTankImage.getCurrentAngle(playerTank));
	        Bitmap bMapRotate = Bitmap.createBitmap(playerTankImage.getFacingUpImage(), 0, 0, playerTankImage.getFacingUpImage().getWidth(), playerTankImage.getFacingUpImage().getHeight(), mat, true);
	        playerTankImage.setFacingUpImage(bMapRotate);

			canvas.drawBitmap(playerTankImage.getFacingUpImage(),
					playerTank.getX(), playerTank.getY(), paint);

			if (!getEnemyTanks().isEmpty()) {

				for (Tank enemy : getEnemyTanks()) {
					canvas.drawBitmap(enemyTankImage.getCurrentImage(enemy),
							enemy.getX(), enemy.getY(), paint);
				}
			}
			if (!getBullets().isEmpty()) {
				for (Bullet bullet : getBullets())
					if (bullet != null)
						canvas.drawBitmap(bulletImage, bullet.getX(),
								bullet.getY(), paint);
			}

			// canvas.drawColor(Color.RED);
			canvas.drawText("Tanks killed: " + points, 0, 780, paint);

		} else {
			gameOver(canvas);
		}
	}

	public void gameOver(Canvas canvas) {
		String msg;
		if (points == 4) {
			msg = "Congratulations, you won! - Click to play again";
		} else {
			msg = "Game Over - Click to play again";
		}
		Paint paint = new Paint();

		FontMetrics metr = paint.getFontMetrics();

		paint.setColor(Color.WHITE);

		canvas.drawText(msg, (getWidth()) / 3, getHeight() / 2, paint);
		// soundManager.close();
	}

	public synchronized void checkGridCollision(Tank tank) {

		if ((tank.getY() > getHeight() - 30) || (tank.getY() < 0)
				|| (tank.getX() > getWidth() - 30) || (tank.getX() < 0)) {

			tank.revertMove();
		}
	}

	public synchronized void checkWallCollision(Tank tank) {
		for (Wall wall : getStructures()) {

			if (!wall.isDestroyed()
					&& (((tank.getY() > wall.getY() - 15) && (tank.getY() < wall
							.getY() + 15)) && ((tank.getX() > wall.getX() - 15) && (tank
							.getX() < wall.getX() + 15)))) {

				tank.revertMove();
			}
		}
	}

	public synchronized void checkCollision() {

		for (Tank enemyTank : enemyTanks) {

			checkGridCollision(enemyTank);
			checkWallCollision(enemyTank);
		}

		List<Bullet> toRemove = new ArrayList<Bullet>();

		if (!getBullets().isEmpty()) {

			for (Bullet bullet : getBullets()) {

				List<GenericCreature> targets = new ArrayList<GenericCreature>();
				targets.addAll(getStructures());

				if (bullet.getParent().getTeam().equals(Tank.TEAM_A)) {
					targets.addAll(getEnemyTanks());
				} else
					targets.add(playerTank);

				for (GenericCreature target : targets) {
					if ((bullet.getX() <= target.getX() + 40)
							&& (bullet.getX() >= target.getX())
							&& (bullet.getY() <= target.getY() + 40)
							&& (bullet.getY() >= target.getY())) {
						if (!target.isDestroyed()) {
							// soundManager.play(SoundManager.HIT_CLIP);
							if (target.isDestructable()) {

								if (target.equals(playerTank)) {

									inGame = false;
								} else if (!(target instanceof Wall)) {

									points++;
									if (points == 4)
										inGame = false;
								}
								target.setDestroyed(true);
							}
							toRemove.add(bullet);
							bullet.getParent().setShotFired(false);
						}
					}
				}
				if ((bullet.getY() > getHeight()) || (bullet.getY() < 0)
						|| (bullet.getX() > getWidth()) || (bullet.getX() < 0)) {
					toRemove.add(bullet);
					bullet.getParent().setShotFired(false);
				}

			}
			bullets.removeAll(toRemove);
		}

	}

	public synchronized void setTank() {
		playerTank = new Tank(50, 50, 12, Direction.UP, Tank.TEAM_A);
	}

	public synchronized void checkFire() {
		for (Bullet bullet : getBullets()) {
			bullet.move();
		}
		for (Tank enemyTank : getEnemyTanks()) {
			if (!enemyTank.isShotFired() && !enemyTank.isDestroyed()
					&& enemyTank.getOrder().equals(Command.SUPPORT_FIRE)) {
				getBullets().add(enemyTank.fire());
			} else {
				enemyTank.manuouver();
			}
		}

	}

	@Override
	/**
	 * View component On Key Down listener method
	 */
	public synchronized boolean onKeyDown(int code, KeyEvent e) {

		int key = e.getKeyCode();
		if ((key == KeyEvent.KEYCODE_DPAD_CENTER)) {
			if (!playerTank.isShotFired()) {
				getBullets().add(playerTank.fire());
				// soundManager.play(SoundManager.SHOT_CLIP);
			}
			return true;
		}
		if (key == KeyEvent.KEYCODE_DPAD_LEFT) {
			playerTank.rotate(Direction.LEFT);
		}

		if (key == KeyEvent.KEYCODE_DPAD_RIGHT) {
			playerTank.rotate(Direction.RIGHT);
		}

		if (key == KeyEvent.KEYCODE_DPAD_UP) {
			playerTank.rotate(Direction.UP);
		}

		if (key == KeyEvent.KEYCODE_DPAD_DOWN) {
			playerTank.rotate(Direction.DOWN);
		}

		playerTank.move();
		checkWallCollision(playerTank);
		checkGridCollision(playerTank);
		return true;
	}

	
	@Override
	/**
	 * View component On Touch listener method
	 */
	public synchronized boolean onTouchEvent(MotionEvent e) {
		if (!inGame) {
			inGame = true;
			initGame();

			return true;
		}
		else {
			return  gestureDetector.onTouchEvent(e);
			
//			addStructure(new Wall(new Float(e.getX()).intValue(),new Float(e.getY()).intValue()));
//			 return true;
		}
		

	}

	public void initWalls(int length, boolean isHorizontal, int position) {
		for (int i = 0; i < length; i++) {
			if (isHorizontal) {
				getStructures().add(new Wall(i * 30 + 50, position));
			} else
				getStructures().add(new Wall(position, i * 30 + 50));
		}
	}

	public void initEnemies() {
		if (!getEnemyTanks().isEmpty()) {
			getEnemyTanks().clear();
		}

		getEnemyTanks().add(
				new Tank(getWidth() - 300, 500, Direction.UP, Tank.TEAM_B));
		getEnemyTanks().add(
				new Tank(getWidth() - 100, 500, Direction.UP, Tank.TEAM_B));
		getEnemyTanks().add(
				new Tank(getWidth() - 50, 500, Direction.UP, Tank.TEAM_B));
		getEnemyTanks().add(
				new Tank(getWidth() - 50, 200, Direction.UP, Tank.TEAM_B));

	}

	private void addStructure(Wall newWall){
		boolean add = true;
		for (Wall e:getStructures()){
			
			if ((Math.abs(newWall.getX()-e.getX())<20)&&(Math.abs(newWall.getY()-e.getY())<20)){
				add = false;
			}

		}if (add) getStructures().add(newWall); 
	}
	public List<Wall> getStructures() {
		return structures;
	}

	public void setStructures(List<Wall> structures) {
		this.structures = structures;
	}

	public void setEnemyTanks(List<Tank> enemyTanks) {
		this.enemyTanks = enemyTanks;
	}

	public List<Tank> getEnemyTanks() {
		return enemyTanks;
	}

	public void setBullets(List<Bullet> bullets) {
		this.bullets = bullets;
	}

	public List<Bullet> getBullets() {
		return bullets;
	}

	public boolean isInGame() {
		return inGame;
	}

	public void setInGame(boolean inGame) {
		this.inGame = inGame;
	}
	
	public Bitmap getBulletImage() {
		return bulletImage;
	}

	public void setBulletImage(Bitmap bulletImage) {
		this.bulletImage = bulletImage;
	}

	public Bitmap getAppleImage() {
		return appleImage;
	}

	public void setAppleImage(Bitmap appleImage) {
		this.appleImage = appleImage;
	}

	public Bitmap getWallImage() {
		return wallImage;
	}

	public void setWallImage(Bitmap wallImage) {
		this.wallImage = wallImage;
	}

	public Bitmap getIntactWallImage() {
		return intactWallImage;
	}

	public void setIntactWallImage(Bitmap intactWallImage) {
		this.intactWallImage = intactWallImage;
	}

	public Bitmap getDestroyedWallImage() {
		return destroyedWallImage;
	}

	public void setDestroyedWallImage(Bitmap destroyedWallImage) {
		this.destroyedWallImage = destroyedWallImage;
	}

	public Bitmap getTankLeftImage() {
		return tankLeftImage;
	}

	public void setTankLeftImage(Bitmap tankLeftImage) {
		this.tankLeftImage = tankLeftImage;
	}

	public Bitmap getTankRightImage() {
		return tankRightImage;
	}

	public void setTankRightImage(Bitmap tankRightImage) {
		this.tankRightImage = tankRightImage;
	}

	public Bitmap getTankUpImage() {
		return tankUpImage;
	}

	public void setTankUpImage(Bitmap tankUpImage) {
		this.tankUpImage = tankUpImage;
	}

	public Bitmap getTankDownImage() {
		return tankDownImage;
	}

	public void setTankDownImage(Bitmap tankDownImage) {
		this.tankDownImage = tankDownImage;
	}

	public Bitmap getTankDestroyedImage() {
		return tankDestroyedImage;
	}

	public void setTankDestroyedImage(Bitmap tankDestroyedImage) {
		this.tankDestroyedImage = tankDestroyedImage;
	}
	
	public Commander getAi() {
		return ai;
	}

	public void setAi(Commander ai) {
		this.ai = ai;
	}

	class TankGestureDetector extends SimpleOnGestureListener {

	    private static final int SWIPE_MIN_DISTANCE = 5;

	    private static final int SWIPE_THRESHOLD_VELOCITY = 12;

	    //necessary to override this so that onFling is called
	    @Override
	    public boolean onDown(MotionEvent e1){
			return true;
	    	
	    }


//	    @Override
//        public boolean onDoubleTap(MotionEvent e) {
//	        playerTank.fire();  
//            return true;
//        }
	    @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
		if (!playerTank.isShotFired()) {
			getBullets().add(playerTank.fire());
			// soundManager.play(SoundManager.SHOT_CLIP);
		}
         return true;
        }
	        @Override
	        public synchronized boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
	            try {

	                // right to left swipe
	                if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
	                    playerTank.setDirection(Direction.LEFT);
		                while(e2.getX()<playerTank.getX()){
		                	playerTank.move();
		                    }
	                }  else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
	                    playerTank.setDirection(Direction.RIGHT);
		                while(e2.getX()>playerTank.getX()){
		                    playerTank.move();}
	                }  else if (e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
	                    playerTank.setDirection(Direction.UP);
		                while(e2.getY()<playerTank.getY()){
		                    playerTank.move();}
	                }  else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
	                    playerTank.setDirection(Direction.DOWN);
		                while(e2.getY()>playerTank.getY()){
		                    playerTank.move();}
	                }

	            } catch (Exception e) {
	                // nothing
	            }
	            return true;
	        }

	    }
}
